package main

import "fmt"

// 第一题
// 定义一个计算n阶乘的递归函数
func factorial(n int) int {
	switch {
	case n < 0:
		panic("n must be non-negative")
	case n == 0:
		return 0
	case n == 1:
		return 1
	}
	return n * factorial(n-1)
}
func factorial2(n int, result int) int {
	switch {
	case n < 0:
		panic("n must be non-negative")
	case n == 0:
		return 0
	case n == 1:
		return result
	}
	return factorial2(n-1, n*result)

}

// 第二题，打印上三角
func triangle(n int) {
	length := ""
	for i := n; i >= 1; i-- {
		if i == 1 {
			length += fmt.Sprint(i)
		} else {
			length += fmt.Sprintf("%d ", i)
		}
	}
	width := len(length)
	for j := width - 1; j >= 0; j-- {
		if length[j] == 32 {
			fmt.Printf("%*s\n", width, length[j:])
		}
	}
	fmt.Println(length)
}

// 第三题，简述defer的作用和应用
func test() {
	fmt.Println(
		`
// defer的作用
// Go语言中的defer语句会将其后面跟随的语句进行延迟处理。在defer归属的函数即将返回时，将延迟处理的语句按defer定义的逆序进行执行，
// 也就是说，先被defer的语句最后被执行，最后被defer的语句，最先被执行。具有延迟调用的特性
// defer的应用
// defer语句能非常方便的处理资源释放问题。比如：资源清理、文件关闭、解锁及记录时间等。文件打开和关闭defer f.Close()、网络连接和断开defer conn.Close()
// 锁的获取和释放defer lock.Release()
// 在Go语言的函数中return语句在底层并不是原子操作，它分为给返回值赋值和RET指令两步。而defer语句执行的时机就在返回值赋值操作后，RET指令执行前。
`)
}
func main() {
	result := factorial(5)
	fmt.Println(result)
	fmt.Println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
	fmt.Println(factorial2(5, 1))
	fmt.Println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
	triangle(12)
	fmt.Println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
	test()
}
